﻿using System;
using Trinity.Framework;
using Trinity.Framework.Helpers;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Windows.Controls;
using Trinity.Components.Combat.Resources;
using Trinity.DbProvider;
using Trinity.Components.Combat.Resources;

using Trinity.Framework;
using Trinity.Framework.Actors.ActorTypes;
using Trinity.Framework.Avoidance;
using Trinity.Framework.Grid;
using Trinity.Framework.Objects;
using Trinity.Framework.Reference;
using Trinity.Framework.Avoidance.Structures;

using Trinity.Components.Adventurer;
using Trinity.UI;
using Trinity.Settings;
using Zeta.Common;
using Zeta.Game;
using Zeta.Game.Internals;
using Zeta.Game.Internals.Actors;


namespace Trinity.Routines.DemonHunter
{
    public sealed class DH_ShadowThreeKnifesXR : DemonHunterBase, IRoutine
    {
        #region Definition

        public string DisplayName => "暗影三刀闲人策略v1.0 beta 4";
        public string Description => "请参考天梯进行配装，护腕推荐使用复仇。\n冰刀电刀均可，推荐冰刀。\n速刷层堆攻速带强者，高层堆范围伤带增痛。\n更多信息请参考下面的链接。";
        public string Author => "闲人（ID:Crazyjay1982）";
        public string Version => "1.0 beta 4";
        public string Url => "http://www.demonbuddy.cn/thread-12665-1-1.html";

        public Build BuildRequirements => new Build
        {
            Sets = new Dictionary<Set, SetBonus>
            {
                { Sets.TheShadowsMantle, SetBonus.Third },
            },
            Items = new List<Item>
            {
                Legendary.HolyPointShot,
				Legendary.KarleisPoint,
				Legendary.ChainOfShadows,
				Legendary.StrongarmBracers,
				Legendary.NemesisBracers,
            },
            Skills = new Dictionary<Skill, Rune>
            {
                { Skills.DemonHunter.Impale, null },
				{ Skills.DemonHunter.ShadowPower, null},
				{ Skills.DemonHunter.Vault, null }
            },
        };

        #endregion

		public override KiteMode KiteMode  => KiteMode.Never;
        public override Func<bool> ShouldIgnoreAvoidance => () => true ;        
        //public bool IsReallyBlocked => (PlayerMover.IsBlocked && Core.BlockedCheck.BlockedTime.TotalMilliseconds > 200) || Core.StuckHandler.IsStuck;
		public bool IsReallyBlocked => PlayerMover.IsBlocked || Core.StuckHandler.IsStuck;
		private bool IsDebugLogOn = false;
		private static List<TrinityActor> ObjectCache => Core.Targets.Entries;
		
		internal static List<TrinityActor> SafeList(bool objectsInAoe = false)
        {
            return
                Core.Targets.Where(x => !x.IsPlayer && (!x.IsUnit || x.IsUnit && x.HitPoints > 0) &&
                                                     (objectsInAoe || !Core.Avoidance.InAvoidance(x.Position))).ToList();
        }
		
		// 找到最近的精英（不要仆从，以防选择到了电风扇），忽略无敌怪
		internal static TrinityActor __BestEliteInRange(float range)
        {				
			return (from u in ObjectCache
                where u.IsUnit &&
					((u.IsElite && u.EliteType != EliteTypes.Minion) || u.IsBoss) &&
					!u.IsInvulnerable && 
					u.Distance <= range
                orderby
					/*u.NearbyUnitsWithinDistance(15f) descending,*/
					u.Distance,
					u.HitPointsPct descending
                select u).FirstOrDefault();
        }
		
		// 找到最合适的小怪
		internal static TrinityActor __BestClusterInRange(float range)
        {	
			return (from u in ObjectCache
                where u.IsUnit && u.IsValid && u.Weight > 0 && !u.IsSafeSpot &&
					u.Distance <= range
                orderby
					u.NearbyUnitsWithinDistance(15f) descending,
					u.Distance,
					u.HitPointsPct descending
                select u).FirstOrDefault();
        }

		internal static TrinityActor __closestUnitInFrontOfMe(float maxDistance, TrinityActor currentTarget)
        {
            var result =
                (from u in ObjectCache
                 where u.IsUnit && u.IsValid && u.Weight > 0 && u.IsInLineOfSight
				 	&& u.Distance <= maxDistance 
                 orderby u.Distance
                 select u).FirstOrDefault();

			if (result == null) 
			{
				result = currentTarget;
			}

            return result;
        }

		internal bool __avoider(AvoidanceNode n)
        {
            return !Core.Avoidance.InAvoidance(n.NavigableCenter);
        }

		internal Vector3 __safePotForVault(TrinityActor currentTarget)
		{
			Vector3 safePot;
			Func<AvoidanceNode, bool> myf = new Func<AvoidanceNode, bool>(__avoider);
			Core.Avoidance.Avoider.TryGetSafeSpot(out safePot, 20f, 50f, Player.Position, myf);
			if (safePot == Vector3.Zero)
			{
				Core.Avoidance.Avoider.TryGetSafeSpot(out safePot, 20f, 50f, Player.Position, null);
			}
			if (safePot == Vector3.Zero)
			{
				safePot = MathEx.CalculatePointFrom(Player.Position, currentTarget.Position, 35);
			}

			return safePot;
		}
		
		public static TrinityActor __BestTargetInRange(float preferRange = 20f, float maxRange = 65f)
        {
            TrinityActor target = __BestEliteInRange(maxRange);
			if (target == null) 
			{
				target = __BestClusterInRange(preferRange);
			}
			if (target == null) 
			{
				target = __BestClusterInRange(maxRange);
			}
			if (target == null)
			{
				target = CurrentTarget;
			}			
			return target;
        }

        public TrinityPower GetOffensivePower()
        {		
			TrinityActor target = CurrentTarget;
			
			if (CurrentTarget.IsInvulnerable)
			{				
				if (IsDebugLogOn)
					Core.Logger.Log(LogCategory.Routine, $"目标有护盾，重新选择目标");
				target = __BestTargetInRange(20f, 65f);
			}
			else 
			{
				// 锁定boss
				if (CurrentTarget.IsBoss || (CurrentTarget.IsElite && CurrentTarget.EliteType != EliteTypes.Minion))
				{
					if (IsDebugLogOn)
						Core.Logger.Log(LogCategory.Routine, $"锁定精英");
				}
				else 
				{
					target = __BestTargetInRange(20f, 65f);
					if (IsDebugLogOn)
						Core.Logger.Log(LogCategory.Routine, $"目标太远，重新选择最合适的目标，新目标距离{target.Distance}");
				}
			}
			
			if (target == null)
			{
				Core.Logger.Warn($"找不到合适的目标");
				return null;
			}

			TrinityActor closestUnit = __closestUnitInFrontOfMe(65f, target);
			float distFromClosetUnit = closestUnit.RadiusDistance;
			
			if (!Skills.DemonHunter.Vault.CanCast() && Player.PrimaryResource > 36)
            {
				if (IsDebugLogOn)
					Core.Logger.Log(LogCategory.Routine, $"戒律耗尽，使用暗影之链激发翻滚");
                return Impale(target);
            }
			
			// 复仇是第一优先的技能，增伤+闪避，能复仇则复仇
			if (Skills.DemonHunter.Vengeance.CanCast())
            {
                return Vengeance();
			}	

			Vector3 safePot = __safePotForVault(target);
			
			// 实在扛不住了赶紧滚蛋。如果是刚刚翻走，则继续站桩输出以保证快速回血
			if (Player.CurrentHealthPct < 0.6 && Core.Avoidance.InAvoidance(Player.Position))
            {
				if (Skills.DemonHunter.Vault.TimeSinceUse < 1700.0)
				{
					if (IsDebugLogOn)
						Core.Logger.Log(LogCategory.Routine, $"刚刚逃出危险区域，站桩输出快速回血, 离上次翻滚时间{Skills.DemonHunter.Vault.TimeSinceUse}");
					return Impale(target);
				}

				if (IsDebugLogOn)
					Core.Logger.Log(LogCategory.Routine, $"在危险区域中且血线太低，开始滚蛋，安全区域距离我{safePot.Distance(Player.Position)}");

				return Vault(safePot);
			}
			if (Player.CurrentHealthPct < 0.4)
            {
				if (Skills.DemonHunter.Vault.TimeSinceUse < 1700.0)
				{
					if (IsDebugLogOn)
						Core.Logger.Log(LogCategory.Routine, $"刚刚逃出危险区域，站桩输出快速回血, 离上次翻滚时间{Skills.DemonHunter.Vault.TimeSinceUse}");
					return Impale(target);
				}

				if (IsDebugLogOn)
					Core.Logger.Log(LogCategory.Routine, $"血线实在太低了，翻滚到安全区域,安全区域距离我{safePot.Distance(Player.Position)} ");
				return Vault(safePot);

			}

			if (Legendary.StrongarmBracers.IsEquipped && Skills.DemonHunter.Vault.TimeSinceUse > Settings.VaultForStrongarmBracers*1000f)
			{
				Vector3 bestAOEPos = TargetUtil.BestAoeUnit(45f, true).Position;
				float distanceFromMe = bestAOEPos.Distance2D(Player.Position);

				if (distanceFromMe < 10f)
				{
					if (IsDebugLogOn)
						Core.Logger.Log(LogCategory.Routine, $"应该使用影轮翻触发力士，但是最佳攻击点离我太近，保持站桩");
				}
				else if (CanVaultTo(bestAOEPos))
				{
					if (IsDebugLogOn)
						Core.Logger.Log(LogCategory.Routine, $"使用影轮翻触发力士，设定值为{Settings.VaultForStrongarmBracers}");
					return Vault(bestAOEPos);
				}
				else 
				{
					if (IsDebugLogOn)
						Core.Logger.Log(LogCategory.Routine, $"应该使用影轮翻触发力士，但找不到合适的位置，保持站桩");
				}
			}
			
			// 减伤残影是第二优先的技能，尽可能的使用暗影触发
            if (Skills.DemonHunter.Vault.TimeSinceUse > 7800.0 && Skills.DemonHunter.ShadowPower.TimeSinceUse > 7800.0)
            {
				if (Skills.DemonHunter.ShadowPower.CanCast())
				{
					Core.Logger.Warn($"使用暗影之力触发残影");
					return ShadowPower();
				}
				else 
				{
					Vector3 bestDPSPos = TargetUtil.BestDpsPosition(Player.Position, 45f);
					
					if (CanVaultTo(bestDPSPos))
					{
						if (IsDebugLogOn)
							Core.Logger.Log(LogCategory.Routine, $"使用影轮翻触发残影，目标：最佳攻击区域");
						return Vault(bestDPSPos);
					}
					else if (CanVaultTo(safePot))
					{
						if (IsDebugLogOn)
							Core.Logger.Log(LogCategory.Routine, $"使用影轮翻触发残影，目标：安全区域");
						return Vault(safePot);
					}
					else 
					{
						if (IsDebugLogOn)
							Core.Logger.Log(LogCategory.Routine, $"无处可去，强制站桩");
					}
				}
			}
			
			// 施放战宠，战宠的有效供给范围是20码
			if (Skills.DemonHunter.Companion.CanCast() && (TargetUtil.NumMobsInRange(20f) > 6 || target.IsBoss || target.IsElite))
			{	
				if (IsDebugLogOn)		
					Core.Logger.Log(LogCategory.Routine, $"在怪群中施放战宠");
				return Companion();
			}

			// 尝试施放死亡印记。为了防止耗尽戒律，死亡印记要设置一个施放间隔
			if (Skills.DemonHunter.MarkedForDeath.CanCast() && Skills.DemonHunter.MarkedForDeath.TimeSinceUse > 2*1000)
			{
				if (!target.HasDebuff(SNOPower.DemonHunter_MarkedForDeath) && !SpellTracker.IsUnitTracked(target, SNOPower.DemonHunter_MarkedForDeath))
				{
					if (IsDebugLogOn)
						Core.Logger.Log(LogCategory.Routine, $"对选择目标施放死亡印记");
					return MarkedForDeath(target);
				}

				if (target != CurrentTarget && !CurrentTarget.HasDebuff(SNOPower.DemonHunter_MarkedForDeath) 
					&& !SpellTracker.IsUnitTracked(CurrentTarget, SNOPower.DemonHunter_MarkedForDeath))
				{
					if (IsDebugLogOn)
						Core.Logger.Log(LogCategory.Routine, $"对当前目标施放死亡印记");
					return MarkedForDeath(CurrentTarget);
				}

				TrinityActor deathTarget = (from u in ObjectCache
                	where u.IsUnit && u.Weight > 0 && u.IsInLineOfSight && !u.IsSafeSpot &&
						!u.HasDebuff(SNOPower.DemonHunter_MarkedForDeath) && !SpellTracker.IsUnitTracked(u, SNOPower.DemonHunter_MarkedForDeath) &&
						u.Distance <= 60f
                	orderby
						u.NearbyUnitsWithinDistance(15f) descending,
						u.Distance,
						u.HitPointsPct descending
                	select u).FirstOrDefault();
				
				if (deathTarget != null)
				{
					if (IsDebugLogOn)
						Core.Logger.Log(LogCategory.Routine, $"新的目标，施放死亡印记");
					return MarkedForDeath(deathTarget);
				}
			}
			
			// 追击目标。困者的影响范围是15码，保证目标在困着的影响范围内。
			if (target.RadiusDistance > 20f)  
			{   
				if (IsDebugLogOn)
					Core.Logger.Log(LogCategory.Routine, $"使用翻滚追击目标，距离{target.RadiusDistance}");

				return CanVaultTo(target.Position) ? Vault(target.Position) : Walk(target.Position, distFromClosetUnit);		
			}
			else if (target.RadiusDistance > 15f )
			{
				if (distFromClosetUnit > 2f) 
				{
					if (IsDebugLogOn)
						Core.Logger.Log(LogCategory.Routine, $"小碎步贴脸目标，距离{distFromClosetUnit}");
					return Walk(target.Position, distFromClosetUnit);
				}
				else 
				{
					if (IsDebugLogOn)
						Core.Logger.Log(LogCategory.Routine, $"距离目标有点远但是走不不过，继续输出");
				}
			}
			
			if (IsReallyBlocked)
			{
				// 如果我还能打到目标，不管是否被挡住，都放刀
				if (Core.Grids.CanRayCast(Player.Position, target.Position))
				{
					if (IsDebugLogOn)
						Core.Logger.Log(LogCategory.Routine, $"进攻中被挡住，仍然攻击目标");
					return Impale(target);
				}
				TrinityActor target2 = TargetUtil.GetClosestUnit(10f);
				Vector3 bestDPSPos = TargetUtil.BestDpsPosition(Player.Position, 45f);
				if (target2!=null)
				{
					if (IsDebugLogOn)
						Core.Logger.Log(LogCategory.Routine, $"进攻中被挡住，杀死阻挡的目标");
					return Impale(target2);
				}	
				else if (CanVaultTo(bestDPSPos))
				{
					if (IsDebugLogOn)
						Core.Logger.Log(LogCategory.Routine, $"尝试向最佳攻击点翻滚以解决卡位");
					return Vault(bestDPSPos);
				}
				else if (CanVaultTo(safePot))
				{
					if (IsDebugLogOn)
						Core.Logger.Log(LogCategory.Routine, $"尝试向安全区域翻滚以解决卡位");
					return Vault(safePot);
				}
				else 
				{
					if (IsDebugLogOn)
						Core.Logger.Log(LogCategory.Routine, $"进攻中被挡住，强制向目标开火");
				}

			}
		
           	if (Skills.DemonHunter.Impale.CanCast())
            {
				if (IsDebugLogOn)
					Core.Logger.Log(LogCategory.Routine, $"我怼怼怼");
                return Impale(target);
            }
			
			//Core.Logger.Warn($"啥也干不了~~~~~");
			
            return null;
        }        

		internal int worldId = 0;
		internal bool needUsePotion = false;
		internal bool needUseShadowPower = false;
		internal int shrines = 0;

        public TrinityPower GetBuffPower()
        {	
			int currentShrineValue = 0;
			if (!Player.IsInTown)
			{
				if (Core.Buffs.HasBlessedShrine)
				{
					currentShrineValue += 1;
				}
				if (Core.Buffs.HasFrenzyShrine)
				{
					currentShrineValue += 10;
				}
				if (Core.Buffs.HasInvulnerableShrine)
				{
					currentShrineValue += 100;
				}
				if (Core.Buffs.HasCastingShrine)
				{
					currentShrineValue += 1000;
				}
				if (Core.Buffs.HasConduitShrine)
				{
					currentShrineValue += 10000;
				}

				if (worldId != Core.Player.WorldSnoId)
				{
					Core.Logger.Log(LogCategory.Routine, $"切换层次了准备卡药水");
					worldId = Core.Player.WorldSnoId;
					needUsePotion = true;
					needUseShadowPower = false;
				}

				if (currentShrineValue != shrines)
				{
					Core.Logger.Log(LogCategory.Routine, $"点圣坛或者水晶塔了，准备卡药水");
					shrines = currentShrineValue;
					needUsePotion = true;
					needUseShadowPower = false;
				}

				//Core.Logger.Log(LogCategory.Routine, $"当前场景ID为{Core.Player.WorldSnoId}，圣坛标记为{hasShrine}，死亡{Core.Player.IsDead}") ;


				if (needUsePotion && Player.CurrentHealthPct < 0.99f && SpellHistory.TimeSinceUse(SNOPower.DrinkHealthPotion) > TimeSpan.FromSeconds(30))
				{					
					needUsePotion = false;
					needUseShadowPower = true;
					//Core.Logger.Log(LogCategory.Routine, $"吃药！！");
					DrinkPotion();
					return null;
				}
				else if (needUsePotion)
				{
					//if (IsDebugLogOn)
					//	Core.Logger.Log(LogCategory.Routine, $"需要吃药但是条件不满足，血线{Player.CurrentHealthPct}，药水用过时间{SpellHistory.TimeSinceUse(SNOPower.DrinkHealthPotion)}");
				}

				if ((needUseShadowPower || needUsePotion) && SpellHistory.TimeSinceUse(SNOPower.DrinkHealthPotion) > TimeSpan.FromSeconds(1) && SpellHistory.TimeSinceUse(SNOPower.DrinkHealthPotion) < TimeSpan.FromSeconds(5))
				{
					Core.Logger.Log(LogCategory.Routine, $"卡药水！！,此时药水耗时{SpellHistory.TimeSinceUse(SNOPower.DrinkHealthPotion)}");
					needUsePotion = false;
					needUseShadowPower = false;
					return ShadowPower();
				}
			}

			if (ShouldShadowPower())
			{
				if (IsDebugLogOn)
					Core.Logger.Log(LogCategory.Routine, $"新的密境或者刚刚死亡，准备卡药水");
				needUsePotion = true;
				needUseShadowPower = false;
                return ShadowPower();
			}
			
            if (Skills.DemonHunter.Vengeance.CanCast() && !Player.IsInTown)
                return Vengeance();
            
			if (Skills.DemonHunter.FanOfKnives.CanCast() && !Player.IsInTown)
				return FanOfKnives();	
			
            return null;
        }

		public bool DrinkPotion()
        {
            var legendaryPotions = Core.Inventory.Backpack.Where(i => i.InternalName.ToLower().Contains("healthpotion_legendary_")).ToList();
            if (legendaryPotions.Any())
            {
				if (IsDebugLogOn)
                	Core.Logger.Log(LogCategory.Routine, "使用传奇药水", 0);
                var dynamicId = legendaryPotions.First().AnnId;
                InventoryManager.UseItem(dynamicId);
                SpellHistory.RecordSpell(new TrinityPower(SNOPower.DrinkHealthPotion));
                SnapShot.Record();
                return true;
            }

            var potion = InventoryManager.BaseHealthPotion;
            if (potion != null)
            {
				if (IsDebugLogOn)
                	Core.Logger.Log(LogCategory.Routine, "使用普通药水", 0);
                InventoryManager.UseItem(potion.AnnId);
                SpellHistory.RecordSpell(new TrinityPower(SNOPower.DrinkHealthPotion));
                SnapShot.Record();
                return true;
            }

			if (IsDebugLogOn)
            	Core.Logger.Log(LogCategory.Routine, "没有可用的药水!", 0);
            return false;
        }

       
        public TrinityPower GetDestructiblePower() => DefaultDestructiblePower();
        public TrinityPower GetDefensivePower() => null;

        public TrinityPower GetMovementPower(Vector3 destination)
        {	
			float dist = destination.Distance2D(Player.Position);
			if (!Player.IsInTown)
			{				
				// 不要为了赶路耗尽憎恨，暗影飞刀只在能量充足的时候放
				if (!Core.Buffs.HasBuff(445266) && Player.PrimaryResource > 36)
				{
					return new TrinityPower(Skills.DemonHunter.Impale);
				}
				// 尽可能的用影轮翻，耗尽戒律也没关系
				if (CanVaultTo(destination) && destination.Distance(Player.Position) > 18f)
				{
					return Vault(destination);
				}
				if (IsReallyBlocked)
				{
					var target = TargetUtil.GetClosestUnit(10f);
					// 找到最近的一个怪，也许就这货把我挡住了，干掉他！
					if (target!=null && Skills.DemonHunter.Impale.CanCast())
					{
						if (IsDebugLogOn)
							Core.Logger.Log(LogCategory.Routine, $"行进中被挡住，开怼");
						return Impale(target);
					}
				}
			}
			
			if (IsDebugLogOn)
				Core.Logger.Log(LogCategory.Routine, $"走向目标，距离={dist}");
            return Walk(destination);
        }

        #region Settings

        public override int ClusterSize => Settings.ClusterSize;
        public override float EmergencyHealthPct => Settings.EmergencyHealthPct;
		public override float ShrineRange => 150f;
		public override int KiteStutterDuration => 800;
        public override int KiteStutterDelay => 800;
        public override int KiteHealthPct => 35;
        public override float KiteDistance => 5f;

        IDynamicSetting IRoutine.RoutineSettings => Settings;
        public DH_ShadowThreeKnifesSettingsXR Settings { get; } = new DH_ShadowThreeKnifesSettingsXR();

        public sealed class DH_ShadowThreeKnifesSettingsXR : NotifyBase, IDynamicSetting
        {
            private int _clusterSize;
            private float _emergencyHealthPct;
			private float _vaultForStrongarmBracers;

            [DefaultValue(11)]
            public int ClusterSize
            {
                get { return _clusterSize; }
                set { SetField(ref _clusterSize, value); }
            }

            [DefaultValue(0.4f)]
            public float EmergencyHealthPct
            {
                get { return _emergencyHealthPct; }
                set { SetField(ref _emergencyHealthPct, value); }
            }

			[DefaultValue(7.0f)]
            public float VaultForStrongarmBracers
            {
                get { return _vaultForStrongarmBracers; }
                set { SetField(ref _vaultForStrongarmBracers, value); }
            }

            #region IDynamicSetting

            public string GetName() => GetType().Name;
            public UserControl GetControl() => UILoader.LoadXamlByFileName<UserControl>(GetName() + ".xaml");
            public object GetDataContext() => this;
            public string GetCode() => JsonSerializer.Serialize(this);
            public void ApplyCode(string code) => JsonSerializer.Deserialize(code, this, true);
            public void Reset() => LoadDefaults();
            public void Save() { }

            #endregion
        }

        #endregion
    }
}


